package com.gitee.melin.bee.util;

import com.gitee.melin.bee.core.jdbc.QueryResult;
import com.google.common.collect.Lists;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.lang.Nullable;

import java.sql.*;
import java.util.LinkedList;

import static com.gitee.melin.bee.util.DateUtils.DEFAULT_DATETIME_FORMAT;
import static com.gitee.melin.bee.util.DateUtils.DEFAULT_DATE_FORMAT;
import static com.gitee.melin.bee.util.DateUtils.DEFAULT_TIME_FORMAT;

public class JdbcUtils {
    private final static Logger logger = LoggerFactory.getLogger(JdbcUtils.class);

    /**
     * 处理查询结果
     *
     * @param result
     * @throws SQLException
     */
    public static QueryResult handleResultSet(ResultSet result, int maxRecords) throws SQLException {
        LinkedList<String> columnNames = Lists.newLinkedList();
        LinkedList<String> columnClassNames = Lists.newLinkedList();
        LinkedList<String> columnTypes = Lists.newLinkedList();
        LinkedList<LinkedList<Object>> rows = Lists.newLinkedList();

        try {
            ResultSetMetaData metaData = result.getMetaData();
            int columnCount = metaData.getColumnCount();

            for (int i = 1; i <= columnCount; i++) {
                String columnName = metaData.getColumnLabel(i);
                String columnType = metaData.getColumnTypeName(i);
                String columnClassName = metaData.getColumnClassName(i);
                columnNames.add(columnName);
                columnTypes.add(columnType);
                columnClassNames.add(columnClassName);
            }

            int count = 0;
            while (result.next()) {
                if (maxRecords > 0) {
                    if (count >= maxRecords) {
                        break;
                    }
                    count++;
                }

                LinkedList<Object> row = Lists.newLinkedList();
                for (int i = 1; i <= columnCount; i++) {
                    Object value = result.getObject(i);
                    String columnType = metaData.getColumnTypeName(i);
                    if (value != null) {
                        if (value instanceof Timestamp) {
                            Timestamp timestamp = (Timestamp) value;
                            value = DateUtils.formatDateTime(timestamp.toInstant());
                        } else if (value instanceof Date) {
                            Date date = (Date) value;

                            if (StringUtils.equalsIgnoreCase("DATE", columnType)) {
                                value = date.toLocalDate().format(DEFAULT_DATE_FORMAT);
                            } else if (StringUtils.equalsIgnoreCase("TIME", columnType)) {
                                value = date.toLocalDate().format(DEFAULT_TIME_FORMAT);
                            } else if (StringUtils.equalsIgnoreCase("DATETIME", columnType)) {
                                value = date.toLocalDate().format(DEFAULT_DATETIME_FORMAT);
                            }
                        } else if ("BIGINT".equals(columnType) || "BIGINT UNSIGNED".equals(columnType)) {
                            value = String.valueOf(value);
                        }
                    }
                    row.add(value);
                }

                rows.add(row);
            }
        } finally {
            org.springframework.jdbc.support.JdbcUtils.closeResultSet(result);
        }

        return new QueryResult(columnNames, columnClassNames, columnTypes, rows);
    }

    public static void closeConnection(@Nullable Connection con) {
        if (con != null) {
            try {
                con.close();
            }
            catch (SQLException ex) {
                logger.debug("Could not close JDBC Connection", ex);
            }
            catch (Throwable ex) {
                // We don't trust the JDBC driver: It might throw RuntimeException or Error.
                logger.debug("Unexpected exception on closing JDBC Connection", ex);
            }
        }
    }

    public static void closeStatement(@Nullable Statement stmt) {
        if (stmt != null) {
            try {
                stmt.close();
            }
            catch (SQLException ex) {
                logger.trace("Could not close JDBC Statement", ex);
            }
            catch (Throwable ex) {
                // We don't trust the JDBC driver: It might throw RuntimeException or Error.
                logger.trace("Unexpected exception on closing JDBC Statement", ex);
            }
        }
    }

    public static void closeResultSet(@Nullable ResultSet rs) {
        if (rs != null) {
            try {
                rs.close();
            }
            catch (SQLException ex) {
                logger.trace("Could not close JDBC ResultSet", ex);
            }
            catch (Throwable ex) {
                // We don't trust the JDBC driver: It might throw RuntimeException or Error.
                logger.trace("Unexpected exception on closing JDBC ResultSet", ex);
            }
        }
    }
}
